/************************************************************************/
// Copyright (C) 2016, han_gangbiao. All rights reserved.
// Use of this source code is governed by a GPL-v2 license that can be found in the License file.
// 
// [Time]:      2016-1-4 21:53:17
// [Author]:    han_gangbiao [http://my.oschina.net/jackhen]
// [Info]:      
/************************************************************************/

#include "sockbase.h"
#include "os_ns_sys_socket.h"

bool sockbase_t::is_valid() const
{
	return m_sockfd != INVALID_SOCKET_FD;
}

int sockbase_t::get_sockfd() const
{
	return this->m_sockfd;
}

void sockbase_t::set_sockfd(int sockfd)
{
	this->m_sockfd = sockfd;
}

int sockbase_t::get_sock_type() const
{
	return this->m_socktype;
}

void sockbase_t::set_sock_type( int socktype )
{
	this->m_socktype = socktype;
}

int sockbase_t::get_local_addr(netaddr_t& local) const
{
	sockaddr_in addr;
	memset(&addr, 0, sizeof(addr));
	int len = sizeof(addr);

	if(netos::getsockname(this->get_sockfd(), (sockaddr*)&addr, &len) == -1)
		return -1;

	local.set_addr(addr);
	return 0;
}

int sockbase_t::get_remote_addr(netaddr_t& remote) const
{
	sockaddr_in addr;
	memset(&addr, 0, sizeof(addr));
	int len = sizeof(addr);

	if(netos::getpeername(this->get_sockfd(), (sockaddr*)&addr, &len) == -1)
		return -1;

	remote.set_addr(addr);
	return 0;
}

int sockbase_t::close()
{
	if( m_sockfd != INVALID_SOCKET_FD && m_sockfd >= 0 )
	{
		if( netos::closesocket(this->get_sockfd()) < 0 )
		{
			this->set_sockfd(INVALID_SOCKET_FD);
			return -1;
		}
		this->set_sockfd(INVALID_SOCKET_FD);
		return 0;
	}
	return -1;
}

int sockbase_t::open(int protocol_family, int type, int protocol, bool reuse_addr)
{
	int one = 1;

	this->set_sockfd( netos::socket(protocol_family, type, protocol) );

	if(this->get_sockfd() == INVALID_SOCKET_FD)
		return -1;
	else if(protocol_family != PF_UNIX && reuse_addr
			&& netos::setsockopt(m_sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&one, sizeof(one)) == -1)
	{
		this->close();
		return -1;
	}
	m_socktype = type;
	return 0;
}

int sockbase_t::set_option(int level, int optname, const char* optval, int optlen)
{
	return netos::setsockopt(this->get_sockfd(), level, optname, optval, optlen);
}

int sockbase_t::get_option(int level, int optname, char* optval, int* optlen)
{
	return netos::getsockopt(this->get_sockfd(), level, optname, optval, optlen);
}

int sockbase_t::set_sock_recv_buf(int len)
{
	int optVal = len;
	int optLen = sizeof(optVal);
	return set_option(SOL_SOCKET, SO_RCVBUF, (const char*)&optVal, sizeof(optLen));
}

int sockbase_t::get_sock_recv_buf()
{
	int optVal = 0;
	int optLen = sizeof(optVal);
	if( get_option(SOL_SOCKET, SO_RCVBUF, (char*)&optVal, &optLen) < 0 )
	{
		return -1;
	}
	return optVal;
}

int sockbase_t::set_sock_send_buf(int len)
{
	int optVal = len;
	int optLen = sizeof(optVal);
	return set_option(SOL_SOCKET, SO_SNDBUF, (const char*)&optVal, sizeof(optLen));
}

int sockbase_t::get_sock_send_buf()
{
    int optVal = 0;
    int optLen = sizeof(optVal);	
    if( get_option(SOL_SOCKET, SO_SNDBUF, (char*)&optVal, &optLen) < 0 )
    {
        return -1;
    }
    return optVal;
}

int sockbase_t::set_nonblock()
{
	return netos::ioctl_nonblock(m_sockfd);
}

int sockbase_t::set_addr_reuse()
{// for server listen
    int one = 1;
    return netos::setsockopt(m_sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&one, sizeof(one));
}

sockbase_t::sockbase_t()
	:m_sockfd(INVALID_SOCKET_FD)
{
}

sockbase_t::sockbase_t(int type, int protocol_family, int protocol /*= 0*/, bool reuse_addr /*= false*/)
	:m_sockfd(INVALID_SOCKET_FD)
{
	this->open(type, protocol_family, protocol, reuse_addr);
}

sockbase_t::~sockbase_t()
{
	close();
}
